/* Copyright (c) 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.orkut.client.api.samples.greetings.client;

import com.google.inject.Singleton;
import com.google.orkut.client.api.samples.greetings.client.DataModel.DataModelUpdateCallback.Type;
import com.google.orkut.client.api.samples.greetings.client.services.AlbumInfo;
import com.google.orkut.client.api.samples.greetings.client.services.PhotoInfo;
import com.google.orkut.client.api.samples.greetings.client.services.UserInfo;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * This class models the data and fires callbacks when data is updated.
 * This is a "Model" in a MVC / MVP pattern.
 *
 * @author Shishir Birmiwal
 */
@Singleton
public class DataModel {
  public static interface DataModelUpdateCallback {
    public enum Type {
      ALBUMS,
      PHOTOS,
      SELECTED_ALBUM,
      SELECTED_RECIPIENTS,
      SELECTED_USER,
      SHARED_ALBUMS,
      USER_INFO_TABLE
    }
    public void update(DataModel data, Type type);
  }
  private final ArrayList<DataModelUpdateCallback> callbacks;
  public AlbumInfo selectedAlbum;
  public final ArrayList<UserInfo> selectedRecipients;
  // TODO: use getters/setters for these
  public UserInfo selectedUser;
  public ArrayList<AlbumInfo> sharedAlbums;
  public HashMap<String, HashMap<String, AlbumInfo>> userAlbumInfo;
  public HashMap<String, HashMap<String, HashMap<String, PhotoInfo>>> userAlbumPhotoInfo;

  public HashMap<String, UserInfo> userInfo;

  public DataModel() {
    userInfo = getNewHashMap();
    userAlbumInfo = getNewHashMap();
    userAlbumPhotoInfo = getNewHashMap();
    sharedAlbums = new ArrayList<AlbumInfo>();
    callbacks = new ArrayList<DataModelUpdateCallback>();
    selectedRecipients = new ArrayList<UserInfo>();
  }

  private void addAlbum(AlbumInfo info) {
    if (!userAlbumInfo.containsKey(info.ownerId)) {
      HashMap<String, AlbumInfo> table = getNewHashMap();
      userAlbumInfo.put(info.ownerId, table);
    }
    userAlbumInfo.get(info.ownerId).put(info.id, info);
  }

  public void addAlbums(ArrayList<AlbumInfo> albums) {
    for (AlbumInfo album : albums) {
      addAlbum(album);
    }
    fireUpdate(Type.ALBUMS);
  }

  private void addPhoto(PhotoInfo info) {
    if (!userAlbumPhotoInfo.containsKey(info.ownerId)) {
      HashMap<String, HashMap<String, PhotoInfo>> table = getNewHashMap();
      userAlbumPhotoInfo.put(info.ownerId, table);
    }
    HashMap<String, HashMap<String, PhotoInfo>> albums = userAlbumPhotoInfo.get(info.ownerId);
    if (!albums.containsKey(info.albumId)) {
      HashMap<String, PhotoInfo> table = getNewHashMap();
      albums.put(info.albumId, table);
    }
    albums.get(info.albumId).put(info.id, info);
  }

  public void addPhotos(ArrayList<PhotoInfo> photos) {
    for (PhotoInfo photo : photos) {
      addPhoto(photo);
    }
    fireUpdate(Type.PHOTOS);
  }

  public void addUserInfo(UserInfo info) {
    userInfo.put(info.id, info);
    fireUpdate(Type.USER_INFO_TABLE);
  }

  public void addUsers(ArrayList<UserInfo> users) {
    for (UserInfo user : users) {
      userInfo.put(user.id, user);
    }
    fireUpdate(Type.USER_INFO_TABLE);
  }

  private void fireUpdate(DataModelUpdateCallback.Type type) {
    for (DataModelUpdateCallback cb : callbacks) {
      cb.update(this, type);
    }
  }

  private <T> HashMap<String, T> getNewHashMap() {
    return new HashMap<String, T>();
  }

  public void registerCallback(DataModelUpdateCallback cb) {
    callbacks.add(cb);
  }

  public void updateLoggedInUser(UserInfo info) {
    selectedUser = info;
    fireUpdate(Type.SELECTED_USER);
    addUserInfo(info);
  }

  public void updateSelectedAlbum(AlbumInfo info) {
    selectedAlbum = info;
    fireUpdate(Type.SELECTED_ALBUM);
  }

  public void updateSelectedRecipients(ArrayList<UserInfo> users) {
    selectedRecipients.clear();
    selectedRecipients.addAll(users);
    fireUpdate(Type.SELECTED_RECIPIENTS);
  }

  public void updateSharedAlbums(ArrayList<AlbumInfo> albums) {
    sharedAlbums.clear();
    sharedAlbums.addAll(albums);
    fireUpdate(Type.SHARED_ALBUMS);
  }
}
